WireGuard Hub-and-Spoke VPN Setup Guide
A step-by-step guide to creating a secure VPN with a central hub and multiple spokes.

Prerequisites
Before you start, gather the public IP addresses of all three virtual machines:
- VM A Public IP:
VM_A_PUBLIC_IP - VM B Public IP:
VM_B_PUBLIC_IP - VM C Public IP:
VM_C_PUBLIC_IP
Step 1: Install WireGuard on All Three VMs
On Ubuntu / Debian:
sudo apt update
sudo apt install wireguard -y
On AlmaLinux / Rocky Linux / RHEL:
# Enable the EPEL repository
sudo dnf install epel-release -y
# Install WireGuard tools
sudo dnf install wireguard-tools -y
Step 2: Generate Keys on All Three VMs
Each VM needs its own unique pair of cryptographic keys. Perform these commands on VM A, VM B, and VM C.
# Create a directory for the keys
mkdir -p ~/.wireguard
cd ~/.wireguard
# Generate the keys
wg genkey | tee privatekey | wg pubkey > publickey
# Secure the private key file
chmod 600 privatekey
# View the keys so you can copy them
echo "--- PUBLIC KEY (Share this) ---"
cat publickey
echo "--- PRIVATE KEY (Keep this secret) ---"
cat privatekey
Important: Copy and paste each VM's public and private key into a text editor. Label them clearly (e.g., "VM A Public Key," "VM B Private Key") so you don't mix them up.
Step 3: Configure the Hub (VM B)
This is the central server. It will listen for connections from VM A and VM C and forward their traffic.
1. Enable IP Forwarding
# Enable forwarding now
sudo sysctl -w net.ipv4.ip_forward=1
# Make it permanent across reboots
echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf
2. Create /etc/wireguard/wg0.conf on VM B
Replace
eth0in thePostUp/PostDownlines with your VM's actual public network interface (find it withip a).
# /etc/wireguard/wg0.conf on VM B (The Hub)
[Interface]
# VM B's private key and tunnel IP
PrivateKey = <PASTE_VM_B_PRIVATE_KEY_HERE>
Address = 10.10.0.1/24
ListenPort = 51820
# Firewall rules to NAT traffic from peers to the internet
PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE
# --- Peer 1: VM A ---
[Peer]
# VM A's public key and assigned tunnel IP
PublicKey = <PASTE_VM_A_PUBLIC_KEY_HERE>
AllowedIPs = 10.10.0.2/32
# --- Peer 2: VM C ---
[Peer]
# VM C's public key and assigned tunnel IP
PublicKey = <PASTE_VM_C_PUBLIC_KEY_HERE>
AllowedIPs = 10.10.0.3/32
Step 4: Configure the Spokes (VM A & VM C)
On VM A — create /etc/wireguard/wg0.conf:
# /etc/wireguard/wg0.conf on VM A (Spoke 1)
[Interface]
PrivateKey = <PASTE_VM_A_PRIVATE_KEY_HERE>
Address = 10.10.0.2/24
[Peer]
PublicKey = <PASTE_VM_B_PUBLIC_KEY_HERE>
Endpoint = <VM_B_PUBLIC_IP>:51820
AllowedIPs = 10.10.0.0/24, 93.184.216.34/32
PersistentKeepalive = 25
On VM C — create /etc/wireguard/wg0.conf:
# /etc/wireguard/wg0.conf on VM C (Spoke 2)
[Interface]
PrivateKey = <PASTE_VM_C_PRIVATE_KEY_HERE>
Address = 10.10.0.3/24
[Peer]
PublicKey = <PASTE_VM_B_PUBLIC_KEY_HERE>
Endpoint = <VM_B_PUBLIC_IP>:51820
AllowedIPs = 10.10.0.0/24, 93.184.216.34/32
PersistentKeepalive = 25
Step 5: Start the Tunnels
Bring the wg0 interface up on all three machines:
sudo wg-quick up wg0
To make WireGuard start automatically on boot:
sudo systemctl enable wg-quick@wg0
Step 6: Verification
1. Check Tunnel Status
On any VM, run sudo wg. You should see your interface details and the latest handshake information for your peers.
2. Ping Across the Tunnel
- From VM A, ping the hub:
ping 10.10.0.1 - From VM A, ping VM C:
ping 10.10.0.3 - From VM C, ping VM A:
ping 10.10.0.2
3. Test the Specific Route
On VM A or VM C, use traceroute to see the path your traffic takes:
# Install if needed: sudo apt install traceroute
traceroute example.com
The first hop should be the hub's tunnel IP (10.10.0.1). This confirms traffic is correctly going through the VPN.
